package com.boot.dog.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.boot.dog.common.constant.SecurityConst;
import com.boot.dog.common.util.ApiResult;
import com.boot.dog.common.util.CommonUtil;
import com.boot.dog.common.util.Result;
import com.boot.dog.entities.pojo.Organization;
import com.boot.dog.entities.pojo.User;
import com.boot.dog.mapper.OrganizationMapper;
import com.boot.dog.mapper.UserMapper;
import com.boot.dog.service.OrganizationService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: MaxLv
 * @Date: 2020/1/16
 */
@Service
@AllArgsConstructor
public class OrganizationServiceImpl implements OrganizationService {

    private final OrganizationMapper organizationMapper;

    private final UserMapper userMapper;

    @Override
    public ApiResult<List<Organization>> getOrgByParentId(Integer parentId, Integer level, Map<Integer, List<Integer>> map) {
        List<Organization> organizations = getOrgByLevel(parentId, (level + 1), map);
        return Result.of(organizations);
    }

    private List<Organization> getOrgByLevel(Integer parentId, Integer level, Map<Integer, List<Integer>> map) {
        Map<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("parentId", parentId);
        paramMap.put("level", parentId == null ? level : null);
        paramMap.put("ids", map == null ? null : map.get(level));
        return organizationMapper.selectOrgByMap(paramMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> saveOrg(Organization org) {
        long count = organizationMapper.selectCount(Wrappers.<Organization>query().lambda().eq(Organization::getTitle, org.getTitle()));
        if (count > 0) {
            return Result.warn("机构名称已存在");
        }
        String orgCode = getOrgCode(CommonUtil.getOrgCode());
        String orgPath = orgCode;
        if (StrUtil.isNotEmpty(org.getOrgPath())) {
            orgPath = StrUtil.join("-", org.getOrgPath(), orgCode);
        }
        org.setOrgCode(orgCode);
        org.setOrgPath(orgPath);
        organizationMapper.insert(org);
        Organization parentOrg = new Organization();
        parentOrg.setId(org.getParentId());
        parentOrg.setLeaf(SecurityConst.AREA_NO_LEAF);
        organizationMapper.updateById(parentOrg);
        return Result.ok("添加机构成功");
    }

    private String getOrgCode(String code) {
        Integer count = organizationMapper.selectCount(Wrappers.<Organization>query().lambda().eq(Organization::getOrgCode, code));
        if (count > 0) {
            code = CommonUtil.getOrgCode();
            return getOrgCode(code);
        }
        return code;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> editOrg(Organization org) {
        long count = organizationMapper.selectCount(Wrappers.<Organization>query().lambda().eq(Organization::getTitle, org.getTitle()).ne(Organization::getId, org.getId()));
        if (count > 0) {
            return Result.warn("机构名称已存在");
        }
        organizationMapper.updateById(org);
        return Result.ok("修改机构成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Void> delById(Integer id) {

        Integer userCount = userMapper.selectCount(Wrappers.<User>query().lambda().eq(User::getOrgId, id));
        if (userCount > 0) {
            return Result.warn("机构下存在监管人员");
        }

        Integer childCount = organizationMapper.selectCount(Wrappers.<Organization>query().lambda().eq(Organization::getParentId, id));
        if (childCount > 0) {
            return Result.warn("存在下级机构");
        }
        organizationMapper.deleteById(id);
        Organization organization = organizationMapper.selectById(id);
        if (organization.getParentId() != 0) {
            Organization parentOrg = new Organization();
            parentOrg.setId(organization.getParentId());
            parentOrg.setLeaf(SecurityConst.AREA_LEAF);
            organizationMapper.updateById(parentOrg);
        }
        return Result.ok("删除机构成功");
    }

    @Override
    public ApiResult<List<Organization>> searchOrg(String title, Map<Integer, List<Integer>> map) {
        if (map != null) {
            List<Organization> organizations = organizationMapper.selectList(Wrappers.<Organization>query().lambda().like(Organization::getTitle, title).or().in(Organization::getId, map.get(SecurityConst.PROVINCE_LEVEL)).or().in(Organization::getId, map.get(SecurityConst.CITY_LEVEL)).or().in(Organization::getId, map.get(SecurityConst.COUNTY_LEVEL)).or().in(Organization::getId, map.get(SecurityConst.STREET_LEVEL)));
            return Result.of(organizations);
        }
        List<Organization> areas = organizationMapper.selectList(Wrappers.<Organization>query().lambda().like(Organization::getTitle, title));
        return Result.of(areas);
    }

    @Override
    public ApiResult<List<Organization>> getAllOrg(Map<Integer, List<Integer>> map) {
        List<Organization> proAreas = getOrgByLevel(null, SecurityConst.PROVINCE_LEVEL, map);
        List<Organization> cityAreas = getOrgByLevel(null, SecurityConst.CITY_LEVEL, map);
        List<Organization> countyAreas = getOrgByLevel(null, SecurityConst.COUNTY_LEVEL, map);
        List<Organization> streetAreas = getOrgByLevel(null, SecurityConst.STREET_LEVEL, map);
        handlerOrgs(streetAreas, countyAreas);
        handlerOrgs(countyAreas, cityAreas);
        handlerOrgs(cityAreas, proAreas);
        return Result.of(proAreas);
    }

    private void handlerOrgs(List<Organization> areas, List<Organization> parentAreas) {
        if (CollUtil.isNotEmpty(areas)) {
            parentAreas.forEach(pArea -> {
                List<Organization> children = areas.stream().filter(area -> pArea.getId().equals(area.getParentId())).collect(Collectors.toList());
                pArea.setChildren(children);
            });
        }
    }
}
